package com.booking.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.booking.common.dto.PageReq;
import com.booking.common.dto.PageResp;
import com.booking.common.enums.BookingErrorCode;
import com.booking.common.exception.BookingException;
import com.booking.common.utils.ConvertUtils;
import com.booking.common.utils.DtUtils;
import com.booking.common.utils.LocalDateTimeUtils;
import com.booking.controller.model.req.grouping.*;
import com.booking.controller.model.req.order.OrderPageQueryReq;
import com.booking.controller.model.res.GroupingDetail;
import com.booking.controller.model.res.GroupingOrderDetail;
import com.booking.dao.entity.GroupingInfo;
import com.booking.dao.entity.GroupingOrder;
import com.booking.dao.service.GroupingInfoService;
import com.booking.dao.service.GroupingOrderService;
import com.booking.enums.GroupingStatusEnums;
import com.booking.enums.OrderPayStatusEnums;
import com.booking.enums.OrderStatusEnums;
import com.booking.service.GroupingService;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Qikai.Lin
 * @date 2023/5/17
 */
@Slf4j
@Service
public class GroupingServiceImpl implements GroupingService {
    @Autowired
    private GroupingInfoService groupingInfoService;
    @Autowired
    private GroupingOrderService groupingOrderService;

    private GroupingInfo getGroupingInfo(Long groupingId) {
        GroupingInfo groupingInfo = groupingInfoService.getById(groupingId);
        if (groupingInfo == null) {
            throw new BookingException(BookingErrorCode.GROUPING_NOT_EXIST);
        }
        return groupingInfo;
    }
    private GroupingOrder getGroupingOrder(Long orderId) {
        GroupingOrder order = groupingOrderService.getById(orderId);
        if (order == null) {
            throw new BookingException(BookingErrorCode.ORDER_NOT_EXIST);
        }
        return order;
    }


    @Override
    public PageResp<GroupingDetail> getAllGroupingInfo(PageReq<GroupingQueryReq> request) {
        PageResp<GroupingInfo> page = groupingInfoService.getPage(request);
        PageResp<GroupingDetail> resPage = new PageResp<>();
        ConvertUtils.copy(resPage, page);

        List<GroupingDetail> resRecord = new ArrayList<>();
        page.getRecords().forEach(info -> {
            resRecord.add(getGroupingInfoDetail(info.getId()));
        });
        resPage.setRecords(resRecord);
        return resPage;
    }

    @Override
    public GroupingDetail getGroupingInfoDetail(Long groupingId) {
        log.info("拼团详情查询 groupingId={}", groupingId);

        // 查询基本信息
        GroupingInfo groupingInfo = getGroupingInfo(groupingId);
        GroupingDetail groupingDetail = ConvertUtils.convert(GroupingDetail.class, groupingInfo);
        groupingDetail.setGroupingDate(DtUtils.getDtStr(groupingInfo.getGroupingDate()));

        // 查询订单信息
        List<GroupingOrder> orders = groupingOrderService.getListByGroupingId(groupingId);
        // 只要拼团中订单
        List<GroupingOrder> groupingOrders = orders.stream()
                .filter(x -> Objects.equals(GroupingStatusEnums.GROUPING.getStatus(), x.getGroupingStatus()))
                .collect(Collectors.toList());
        // 如果没有拼团中订单，则无详情
        if (groupingOrders.size() == 0) {
            groupingDetail.setGroupingState(GroupingStatusEnums.GROUPED.getMsg());
            groupingDetail.setNeedCount(0);
            return groupingDetail;
        }
        groupingDetail.setGroupingState(GroupingStatusEnums.GROUPING.getMsg());
        groupingDetail.setNeedCount(groupingInfo.getFollowCount() - groupingOrders.size());
        return groupingDetail;
    }

    @Override
    public PageResp<GroupingOrderDetail> getGroupingOrderPage(PageReq<OrderPageQueryReq> request) {
        return null;
    }

    @Override
    public GroupingOrderDetail getGroupingOrderDetail(Long orderId) {
        // 查询拼团订单
        GroupingOrder groupingOrder = getGroupingOrder(orderId);
        GroupingOrderDetail orderDetail = ConvertUtils.convert(GroupingOrderDetail.class, groupingOrder);

        // 查询拼团信息
        GroupingInfo groupingInfo = getGroupingInfo(groupingOrder.getGroupingId());
        // 填充拼团信息
        ConvertUtils.copy(orderDetail, groupingInfo);
        orderDetail.setGroupingName(groupingInfo.getName());
        orderDetail.setCreatorId(groupingInfo.getCreatorId());

        // 填充订单信息
        orderDetail.setOrderId(groupingOrder.getId());
        // 转化日期
        orderDetail.setBookingDate(LocalDateTimeUtils.toYyyyMMddStr(groupingOrder.getCreatedTime()));
        orderDetail.setGroupingDate(LocalDateTimeUtils.toYyyyMMddStr(groupingInfo.getGroupingDate()));

        // 转化状态
        orderDetail.setOrderStatus(OrderStatusEnums.getMsgByStatus(groupingOrder.getOrderStatus()));
        orderDetail.setPayStatus(OrderPayStatusEnums.getMsgByStatus(groupingOrder.getPayStatus()));
        orderDetail.setGroupingStatus(GroupingStatusEnums.getMsgByStatus(groupingOrder.getGroupingStatus()));

        return orderDetail;
    }

    @Override
    public Long createGrouping(GroupingCreateReq request) {
        log.info("拼团活动创建 request={}", JSON.toJSONString(request));
        GroupingInfo groupingInfo = ConvertUtils.convert(GroupingInfo.class, request);
        groupingInfo.setId(IdWorker.getId());
        groupingInfo.setCreatorId(request.getUserId());
        groupingInfo.setGroupingDate(LocalDateTimeUtils.yyyyMMddStrToLocalDateTime(request.getGroupingDate()));
        // TODO 根据活动介绍打标签
        groupingInfo.setTagList("");
        groupingInfoService.save(groupingInfo);
        log.info("拼团活动创建成功！ groupingId={}", groupingInfo.getId());
        return groupingInfo.getId();
    }

    @Override
    public void updateGrouping(GroupingUpdateReq request) {
        log.info("拼团活动更新 request={}", JSON.toJSONString(request));
        // 查询拼团信息
        GroupingInfo groupingInfo = getGroupingInfo(request.getGroupingId());
        ConvertUtils.copy(groupingInfo, request);
        if (Strings.isNotEmpty(request.getGroupingDate())) {
            groupingInfo.setGroupingDate(LocalDateTimeUtils.yyyyMMddStrToLocalDateTime(request.getGroupingDate()));
        }
        groupingInfoService.updateById(groupingInfo);
        log.info("拼团活动更新成功！ groupingId={}", groupingInfo.getId());
    }

    @Override
    public Long followGrouping(GroupingOrderFollowReq request) {
        log.info("参与拼团 request={}", JSON.toJSONString(request));
        // 查询拼团信息
        GroupingInfo groupingInfo = getGroupingInfo(request.getGroupingId());

        // 判断是否还能拼团
        List<GroupingOrder> groupingOrders = groupingOrderService.getListByGroupingId(groupingInfo.getId());
        if (groupingOrders.size() >= groupingInfo.getFollowCount()) {
            throw new BookingException(BookingErrorCode.GROUPED_ALREADY);
        }

        // 创建拼团订单
        GroupingOrder groupingOrder = new GroupingOrder();
        groupingOrder.setId(IdWorker.getId());
        groupingOrder.setGroupingId(request.getGroupingId());
        groupingOrder.setVisitorId(request.getUserId());
        groupingOrder.setOrderStatus(OrderStatusEnums.INIT.getStatus());
        groupingOrder.setPayStatus(OrderPayStatusEnums.NOT_PAY.getStatus());
        groupingOrder.setGroupingStatus(GroupingStatusEnums.GROUPING.getStatus());
        // 设置支付价格：拼团价格/拼团人数
        groupingOrder.setTotalPrices(groupingInfo.getPrices().divide(new BigDecimal(groupingInfo.getFollowCount()), RoundingMode.UP));
        groupingOrder.setBookingPrices(groupingInfo.getBookingPrices().divide(new BigDecimal(groupingInfo.getFollowCount()), RoundingMode.UP));
        // 存储拼团记录
        groupingOrderService.save(groupingOrder);

        // 判断是否成团：拼团订单数=拼团活动所需人数
        List<GroupingOrder> groupingOrderList = groupingOrderService.getListByGroupingId(groupingInfo.getId());
        if (groupingOrderList.size() == groupingInfo.getFollowCount()) {
            log.info("拼团人数足够，订单已成团 groupingId={}", groupingInfo.getId());
            // 已成团，将拼团订单状态改为已成团
            groupingOrderList.forEach(order -> {
                order.setGroupingStatus(GroupingStatusEnums.GROUPED.getStatus());
            });
            groupingOrderService.updateBatchById(groupingOrderList);
            log.info("拼团订单状态更新成功! groupingId={}", groupingInfo.getId());
        }
        log.info("参与拼团成功！ orderId={}", groupingOrder.getId());
        return groupingOrder.getId();
    }

    @Override
    public void deleteGrouping(Long groupingId) {
        log.info("拼团删除 groupingId={}", groupingId);
        groupingInfoService.removeById(groupingId);
        log.info("拼团删除成功 groupingId={}", groupingId);
    }

    @Override
    public void cancelGroupingOrder(Long orderId) {
        log.info("拼团订单删除 orderId={}", orderId);
        groupingOrderService.removeById(orderId);
        log.info("拼团订单成功 orderId={}", orderId);
    }

    @Override
    public void payGroupingOrderBooking(Long orderId) {
        log.info("拼团订单支付定金 orderId={}", orderId);
        GroupingOrder order = getGroupingOrder(orderId);
        // 是否支付定金
        if (Objects.equals(OrderPayStatusEnums.BOOKING_PAYED.getStatus(), order.getPayStatus())) {
            throw new BookingException(BookingErrorCode.BOOKING_PAYED);
        }
        // 更新房间订单定金支付状态
        order.setOrderStatus(OrderStatusEnums.BOOKING.getStatus());
        order.setPayStatus(OrderPayStatusEnums.BOOKING_PAYED.getStatus());
        groupingOrderService.updateById(order);
        log.info("支付成功！");
    }

    @Override
    public void payGroupingOrder(Long orderId) {
        log.info("拼团订单支付全款 orderId={}", orderId);
        GroupingOrder order = getGroupingOrder(orderId);
        // 是否已支付
        if (Objects.equals(OrderPayStatusEnums.PAYED.getStatus(), order.getPayStatus())) {
            throw new BookingException(BookingErrorCode.ORDER_ALREADY_PAYED);
        }
        // 更新订单支付状态
        order.setOrderStatus(OrderStatusEnums.BOOKING.getStatus());
        order.setPayStatus(OrderPayStatusEnums.PAYED.getStatus());
        groupingOrderService.updateById(order);
        log.info("支付成功！");
    }

    @Override
    public void finishOrder(Long orderId) {
        log.info("拼团订单完成 orderId={}", orderId);
        GroupingOrder order = getGroupingOrder(orderId);
        // 是否已成团
        if (!Objects.equals(GroupingStatusEnums.GROUPED.getStatus(), order.getGroupingStatus())) {
            throw new BookingException(BookingErrorCode.NO_GROUPED);
        }
        // 更新订单状态
        order.setOrderStatus(OrderStatusEnums.END.getStatus());
        groupingOrderService.updateById(order);
        log.info("订单完成！");
    }
}
